#pragma once

// #include "GLTFLoader.h"
#include <d3d12.h>
#include <cstdint>
#include "Selah.h"

using namespace SL;

struct TestApp : public Application
{
    TestApp(const SL::AppConfig& config) : Application(config) {}

    virtual void onInitialize() override {}
    virtual void onFixedUpdate() override {} // physics, AI, etc
    virtual void onResize() override {}

    virtual void onUpdate(float dt) override; // animation
    virtual void onShutdown() override;
    virtual void onLoad() override; // assets resources
    virtual void onFrameRender() override;
    virtual void onGuiRender() override;

    virtual ~TestApp() = default;

    // virtual void OnGamepadEvent(const GamepadEvent& gamepadEvent) {}
    // virtual void OnGamepadState(const GamepadState& gamepadState) {}
    // virtual void OnDroppedFile(const std::filesystem::path& path) {}
    virtual bool onMouseEvent(const SL::MouseEvent&) override;
    virtual bool onKeyboardEvent(const SL::KeyboardEvent&) override;

private:
    ID3D12RootSignature* rootSignatureCube;
    ID3D12PipelineState* pipelineStateCube;
    ID3D12RootSignature* rootSignatureSkybox;
    ID3D12PipelineState* pipelineStateSkybox;
    ID3D12RootSignature* rootSignatureTonemapping;
    ID3D12PipelineState* pipelineStateTonemapping;

    ID3D12Resource* vertexBuffer;
    ID3D12Resource* indexBuffer;
    ID3D12Resource* uploadBuffer;
    ID3D12Resource* constantBuffer;
    ID3D12Resource* skyboxTexture;
    D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
    D3D12_INDEX_BUFFER_VIEW indexBufferView;
    D3D12_GPU_DESCRIPTOR_HANDLE skyboxHandleGPU;
    D3D12_CPU_DESCRIPTOR_HANDLE skyboxHandleCPU;

    void populateCommandList();
    void prepareGraphicsPipeline();

    void uploadResourceBuffer(const void* pData, size_t dataSize, ID3D12Resource** ppResource, D3D12_RESOURCE_STATES afterState);
    void uploadResourceTexture(
        UINT width,
        UINT height,
        ID3D12Resource** ppResource,
        D3D12_RESOURCE_STATES afterState,
        UINT NumSubresources,
        const D3D12_SUBRESOURCE_DATA* pSrcData
    );
    void uploadResourceHDR(
        UINT width,
        UINT height,
        ID3D12Resource** ppResource,
        D3D12_RESOURCE_STATES afterState,
        UINT NumSubresources,
        const D3D12_SUBRESOURCE_DATA* pSrcData
    );
    void loadModels();
    void loadTextures();
    void loadHDR();

    Camera camera;
    CameraController* cameraController;
    float2 cur_mouse;
    float exposure = 0.0;
    float Kd = 0.5;
    char m_char;

    // clang-format off
    Constants local_constants[APP_NUM_BACK_BUFFERS];
    std::vector<Vertex>cubeVertices;
    std::vector<uint32_t>indices;
    double frameTime;
};